package com.m4f.city.web.controller.admin;

import java.util.List;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.cache.CacheException;
import javax.validation.Valid;

import org.springframework.security.access.annotation.Secured;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.m4f.city.business.domain.Application;
import com.m4f.city.business.domain.Company;
import com.m4f.city.business.security.InternalUserDetailService;
import com.m4f.city.utils.table.DataTable2;
import com.m4f.city.web.controller.BaseController;
import com.m4f.city.web.form.ApplicationForm;
import com.m4f.gaeweb.web.utils.StackTraceUtil;

@Controller
@Secured(InternalUserDetailService.ROLE_ROOT)
@RequestMapping("/admin/application")
public class ApplicationAdminController extends BaseController {
	private static final Logger LOGGER = Logger.getLogger(ApplicationAdminController.class.getName());
	
	public ApplicationAdminController() throws CacheException {
		super();
	}
	
	@RequestMapping(method=RequestMethod.GET)
	public String getForm(Model model, Locale locale) {
		try {
			Application app = this.serviceLocator.getApplicationService().create();	
			model.addAttribute("form", new ApplicationForm(app));
		} catch(Exception e) {
			LOGGER.severe(StackTraceUtil.getStackTrace(e));
			return "common.error";
		}
		return "admin.application.edit";
	}
	
	@RequestMapping(method=RequestMethod.POST)
	public String save(@ModelAttribute("form") @Valid ApplicationForm form, 
			BindingResult result, Model model, Locale locale) {
		boolean updateAction = false;
		try {
			if(result.hasErrors()) {
				return "admin.application.edit";
			}
			
			Application app = form.getApplication();
			Md5PasswordEncoder encoder = new Md5PasswordEncoder();
			Object salt = null;
			app.setClientId(encoder.encodePassword(app.getName(), salt)); // TODO double encoding???
			app.setClientSecret(encoder.encodePassword(app.getName()+"2010", salt)); // TODO modify the hardcoded date
			if(app.getId() != null)  updateAction = true;
			this.serviceLocator.getApplicationService().save(app);
			if(updateAction) addSuccessMessage("message.success.admin.application.updated");
			else addSuccessMessage("message.success.admin.application.created");
		} catch(Exception e) {
			if(updateAction) addErrorMessage("message.error.admin.application.updated");
			else addErrorMessage("message.error.admin.application.created");
			LOGGER.severe(StackTraceUtil.getStackTrace(e));
			return "common.error";
		}
		
		return getRedirect("/admin/application/list", locale);
	}
	
	@RequestMapping(value="/list", method=RequestMethod.GET)
	public String list() {
		return "admin.application.list";
	}
	
	@RequestMapping(value="/edit/{appId}", method=RequestMethod.GET)
	public String edit(@PathVariable Long appId, Model model, Locale locale) {
		try {
			Application app = this.serviceLocator.getApplicationService().getObjectById(appId);
			
			model.addAttribute("form", new ApplicationForm(app));

		} catch(Exception e) {
			LOGGER.severe(StackTraceUtil.getStackTrace(e));
			return "common.error";
		}
		return "admin.application.edit";
	}
	
	@RequestMapping(value="/delete/{appId}", method=RequestMethod.GET)
	public String delete(@PathVariable Long appId, Locale locale) {
		try {
			Application app = this.serviceLocator.getApplicationService().getObjectById(appId);
			this.serviceLocator.getApplicationService().delete(app);
			addSuccessMessage("message.success.admin.application.deleted");
		} catch(Exception e) {
			addErrorMessage("message.error.admin.application.deleted");
			LOGGER.severe(StackTraceUtil.getStackTrace(e));
			return "common.error";
		}
		
		return getRedirect("/admin/application/list", locale);
	}
	
	@RequestMapping(value="/detail/{appId}", method=RequestMethod.GET)
	public String detail(@PathVariable Long appId, Model model, Locale locale) {
		try {
			Application app = this.serviceLocator.getApplicationService().getObjectById(appId);
			model.addAttribute("application", app);
			Company company = this.serviceLocator.getCompanyService().getObjectById(app.getCompanyId());
			model.addAttribute("company", company);
		} catch(Exception e) {
			LOGGER.severe(StackTraceUtil.getStackTrace(e));
			return "common.error";
		}
		return "admin.application.detail";
	}

	@ModelAttribute("companies")
	public List<Company> getCompanies() throws Exception {
		return this.serviceLocator.getCompanyService().getAll();
	}
	
	// TESTING
		
	@RequestMapping(value="/list/table")
	@ResponseBody
	public DataTable2<Application> table3(@RequestParam(required=false) Integer iDisplayStart, @RequestParam(required=false) Integer iDisplayLength, /* Pagination */
			@RequestParam(required=false) Integer iSortCol_0, @RequestParam(required=false) String sSortDir_0, /* Sorting */
			@RequestParam(required=false, defaultValue="") String sSearch /* Search */) {
		try {
			
			// Filter 
			// TODO Now its difficult to filter by columns. So there is a general filter and here we have to set the default column to filter.
			String filterBy = "name";
			String filterValue = sSearch;
			// End filter
			
			DataTable2<Application> table = iDisplayLength != null ?
					new DataTable2<Application>(new String[]{"id", "name"}, sSortDir_0, iDisplayStart, iDisplayLength) :
					new DataTable2<Application>(new String[]{"id", "name"}, sSortDir_0, iDisplayStart);
			table.setRows(this.serviceLocator.getApplicationService().getObjectsBy(table.getOrdering(iSortCol_0), filterBy, filterValue, table.getStart(), table.getEnd()));
			table.setiTotalDisplayRecords(this.serviceLocator.getOrganizationService().countOrganization()); // TODO 
			return table;
		} catch(Exception e) {
			LOGGER.log(Level.SEVERE, StackTraceUtil.getStackTrace(e));
			return new DataTable2<Application>();
		}
	}	
	
	@RequestMapping(value="/company/description")
	@ResponseBody
	public String getCompanyDescription(@RequestParam(required=true) Long companyId) {
		try {
			Company company = this.serviceLocator.getCompanyService().getObjectById(companyId);
			return company != null ? company.getName() : String.valueOf(companyId);
		} catch(Exception e) {
			LOGGER.log(Level.SEVERE, StackTraceUtil.getStackTrace(e));
			return String.valueOf(companyId);
		}
	}	
}